/* Copyright (C) 2013 Interactive Brokers LLC. All rights reserved. This code is subject to the terms
 * and conditions of the IB API Non-Commercial License or the IB API Commercial License, as applicable. */
// Rename shared_ptr to shared_ptr_ib
#ifndef shared_ptr_h_INCLUDED
#define shared_ptr_h_INCLUDED

namespace IBOfficial
{
	//
	// Implements a subset of shared_prt found at www.boost.org.
	// Uses a singly linked circular list instead of a reference counter.
	// Avoids extra heap allocation needed to get a shared reference counter,
	// but sizeof(shared_ptr) == sizeof(void*) * 3 compared to sizeof(void*) * 2
	//
	// See "Handles and Exception Safety, Part 4: Tracking References without Counters"
	// by Andrew Koenig and Barbara E. Moo, Feb. 2003 C++ Users Journal
	//
	namespace shared_ptr_defs {

		class Use {
		public:

			Use() { forward_ = this; back_ = this; }
			~Use() { remove(); }

			Use(const Use& u) { insert(u); }
			Use& operator=(const Use& u)
			{
				if (this != &u) {
					remove();
					insert(u);
				}
				return *this;
			}
			bool only() const { return this == this->forward_; }
		private:
			mutable const Use *forward_;
			mutable const Use *back_;

			void insert(const Use& u) const {
				this->back_ = &u;
				this->forward_ = u.forward_;
				u.forward_->back_ = this;
				u.forward_ = this;
			}

			void remove() const {
				this->forward_->back_ = this->back_;
				this->back_->forward_ = this->forward_;
			}
		};

	} // end of namespace shared_ptr_defs

	template<typename X> class shared_ptr_ib {
	public:

		typedef shared_ptr_defs::Use Use;

		template<typename Y> friend class shared_ptr_ib;

		explicit shared_ptr_ib(X* ptr = 0) : ptr_(ptr) {}

		~shared_ptr_ib() { if (use_.only()) delete ptr_; }

		template<typename Y>
		shared_ptr_ib(const shared_ptr_ib<Y>& other)
			: ptr_(other.ptr_),
			use_(other.use_)
		{}

		shared_ptr_ib& operator=(const shared_ptr_ib& other) {
			if (&use_ == &other.use_) { return *this; }
			if (use_.only()) { delete ptr_; }
			use_ = other.use_;
			ptr_ = other.ptr_;
			return *this;
		}

		X& operator*()  const { return *ptr_; }
		X* operator->() const { return ptr_; }
		X* get()        const { return ptr_; }
		bool only() const { return use_.only(); }

		void reset(X* ptr = 0) {
			if (use_.only()) { delete ptr_; }
			ptr_ = ptr;
			use_ = Use();
		}

	private:

		X *ptr_;
		Use use_;
	};
}

#endif /* shared_ptr_h_INCLUDED */
